home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
PROGRAM
/
MISCPAS.ARJ
/
TOADADD.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1992-06-23
|
9KB
|
245 lines
----TOADADD.DOC----
TOADADD.PAS
Turbo Pascal Inline routines for MS-DOS systems.
First release permits you to add numeric strings to numeric strings,
or integers to numeric strings.
Sounds simple, but this gives you a handle on manipulating literally
infinitely large numbers. (When the number depicts more than the
number of objects in the universe, that's a pretty good definition
of infinite, ne?)
Code could be rewritten to permit use with Z80 systems, but I'll leave
that as an exercise to the student. (Don't you just HATE that?)
More to follow ... subtraction, multiplication, division, etc.
(Keep your eyes peeled for TOADMATH.PAS.) (Unless some other Netlandian
beats me to it.)
Assembler ideas obtained from Chapter 11, "Assembler for the IBM PC and
PC-XT", by Peter Abel ((C) 1984 Reston Publishing Company, Inc.)
for the usual ripoff price.
Works just fine on an 80286 PC clone running PC-DOS 3.1 and Turbo 3.0
.. should be fine on any MS-DOS system and any Turbo version.
Released to the public domain. (Yep, it's my code.)
David Kirschbaum
Toad Hall
ABN.ISCAMS@USC-ISID.ARPA
----TOADADD.PAS----
program TOADADD.PAS;
{David Kirschbaum
Toad Hall
ABN.ISCAMS@USC-ISID.ARPA
7573 Jennings Lane
Fayetteville NC 28303
(919) 868-3471
Released to the public domain. For MS-DOS systems and Turbo Pascal.
}
{Methods to provide integer addition for huge numbers ..
Presently limited by Turbo Pascal's limitation of string
variables to 255 bytes.
You COULD use an array for this, extending the length of
your number string to available memory!
String must be in Data Segment, and should be of the
format '0000001' or '003270' or whatever.
YES, it MUST be zero-filled, and NO commas or decimals!
(We're talking multi-character integers here, remember.)
}
TYPE
Str20 = STRING[20];
var
NrStr,
IntStr : Str20;
i,code : INTEGER;
PROCEDURE Addit;
{adds two integer strings together.}
BEGIN
Inline(
$1E { push DS}
/$07 { pop ES ;ES=DS}
/$31/$DB { xor BX,BX ;clear msbs}
/$89/$D9 { mov CX,BX}
/$8A/$0E/>NrStr { mov CL,[>NrStr] ;the shorter number}
/$E3/$2B { jcxz Exit ;no length, forget it}
/$8A/$1E/>IntStr { mov BL,[>IntStr] ;string length}
/$8D/$B7/>IntStr { lea SI,>IntStr[BX] ;first char}
/$89/$F7 { mov DI,SI ;source=destination}
/$88/$CB { mov BL,CL ;NrStr length again}
/$8D/$9F/>NrStr { lea BX,>NrStr[BX] ;point to last char}
/$51 { push CX ;save IntStr length}
/$56 { push SI ;and offsets}
/$F8 { clc}
/$FD { std ;direction right to left}
/$B4/$00 {B20: mov AH,0 ;clear AH}
/$AC { lodsb ;load IntStr byte}
/$12/$07 { adc AL,[BX] ;add NrStr val}
/$37 { aaa ;adjust for Ascii}
/$AA { stosb ;store sum in IntStr}
/$4B { dec BX ;back up NrStr}
/$E2/$F6 { loop B20}
/$88/$25 { mov [DI],AH ;at end, store carry}
/$5E { pop SI ;back to the end again}
/$89/$F7 { mov DI,SI ;source=destination}
/$59 { pop CX ;get back NrStr length}
/$41 { inc CX ;anticipate the carry}
/$AC {B30: lodsb ;snarf the new val}
/$0C/$30 { or AL,$30 ;ascify it}
/$AA { stosb}
/$E2/$FA { loop B30}
{exit:}
);
END;
{Another method:
Lets you add an integer to ANY global string variable.
Both the integer to be added, and the address of the
string variable are brought in as parameters.
}
PROCEDURE Add(nr : INTEGER; VAR S : Str20);
{could also be:
PROCEDURE Add(nr : INTEGER; VAR S);
using Turbo's untyped parameter capability.
use a string variable S brought in as a parameter,
and the integer nr, also brought in as a parameter.
}
BEGIN
Inline(
$8B/$86/>NR { mov AX,>nr[BP] ;nr of spins}
/$09/$C0 { or AX,AX ;anything there?}
/$74/$27 { je X1 ; nope, quit this mess}
/$8B/$9E/>S { mov BX,>S[BP] ;snarf the string address.}
{ ;(LDS or LES would also work,}
{ ;but we're assuming S is a global}
{ ;variable .. makes it much simpler.)}
/$89/$DF { mov DI,BX ;offset to S}
/$43 { inc BX ;bump past length byte}
/$31/$C9 { xor CX,CX ;clear msb}
/$8A/$0D { mov CL,[DI] ;get our integer string length}
/$01/$CF { add DI,CX ;point to the last char in the string}
{;}
/$BE/$0A/$00 { mov SI,10 ; put divisor in SI}
/$31/$D2 {L1:xor DX,DX ; clear dividend high word}
/$80/$2D/$30 { sub byte ptr [DI],'0' ;deasciize the char}
/$02/$05 { add AL,[DI] ;add our integer msb to the char val}
/$F7/$F6 { div SI ; AX = (DX:AX)/SI, DX = remainder}
/$80/$C2/$30 { add DL,'0' ; convert DL remainder byte to ascii}
/$88/$15 { mov byte ptr [DI],DL ; put back in string as char}
/$4F { dec DI ; back step in string}
/$39/$DF { cmp DI,BX ;hit start?}
/$76/$04 { jbe X1 ; yep, done}
/$09/$C0 { or AX,AX ; all done? (AX = 0?)}
/$75/$E9 { jne L1 ; if not, do another digit}
); {X1:}
END; {of Add}
{A third method, assuming you'll only have ONE global
string variable you'll ALWAYS use for this adding.
(In this demo, that's IntStr.)
Saves a little time by not having to pass another parm.
}
PROCEDURE Add_Int(nr : INTEGER);
{ use a global string variable (in this case, IntStr),
and the integer nr, brought in as a parameter.
}
BEGIN
Inline(
$8B/$86/>NR { mov AX,>nr[BP] ;nr of spins}
/$09/$C0 { or AX,AX ;anything there?}
/$74/$26 { je X2 ; nope, quit this mess}
/$BB/>IntStr { mov BX,>IntStr ;snarf the string address.}
{;or could be}
{; lea BX,>IntStr}
{;(LDS or LES would also work, but we're assuming}
{; IntStr is a global variable .. makes it much}
{; simpler, and we don't chance messing up DS.)}
/$89/$DF { mov DI,BX ;offset to IntStr}
/$43 { inc BX ;bump past length byte}
/$31/$C9 { xor CX,CX ;clear msb}
/$8A/$0D { mov CL,[DI] ;get our integer string length}
/$01/$CF { add DI,CX ;point to the last char in the string}
{;}
/$BE/$0A/$00 { mov SI,10 ; put divisor in SI}
/$31/$D2 {L2:xor DX,DX ; clear dividend high word}
/$80/$2D/$30 { sub byte ptr [DI],'0' ;deasciize the char}
/$02/$05 { add AL,[DI] ;add our integer msb to the char val}
/$F7/$F6 { div SI ; AX = (DX:AX)/SI, DX = remainder}
/$80/$C2/$30 { add DL,'0' ; convert DL remainder byte to ascii}
/$88/$15 { mov byte ptr [DI],DL ; put back in string as char}
/$4F { dec DI ; back step in string}
/$39/$DF { cmp DI,BX ;hit start?}
/$76/$04 { jbe X2 ; yep, done}
/$09/$C0 { or AX,AX ; all done? (AX = 0?)}
/$75/$E9 { jne L2 ; if not, do another digit}
); {X2:}
END; {of Add_Int}
PROCEDURE Continue;
VAR ch : CHAR;
BEGIN
Write('Press any key to continue: ');
Repeat until keypressed; read(kbd,ch);
Writeln;
END;
begin
NrStr := '004';
IntStr := '00000000000000000000';
Writeln('First add one number string [',NrStr,']');
Writeln('to a second number string [',IntStr,']');
Write(IntStr, ' + ', NrStr, ' = ');
Addit;
Writeln(IntStr);
Continue;
Writeln('Now, add an integer to a number string:');
FOR i := 1 TO 10 DO BEGIN
Write(IntStr, ' + ', i:2, ' = ');
Add(i,IntStr);
Writeln(IntStr);
END;
Continue;
Writeln('Same process, but using the number string as a global:');
FOR i := 1 TO 10 DO BEGIN
Write(IntStr, ' + ', i:2, ' = ');
Add_Int(i);
Writeln(IntStr);
END;
Continue;
Writeln('Flashy, user-friendly interactive demo.');
Writeln('Enter a positive number string (up to 19 chars).');
Writeln('(Enter a null line (CR) to quit): ');
Repeat
Readln(NrStr);
IF length(NrStr) > 19 THEN NrStr[0] := #19; {truncate}
IF NrStr <> '' THEN BEGIN
Write(IntStr, ' + ', NrStr, ' = ');
Addit;
Writeln(IntStr);
END;
Until NrStr = '';
end.